 package IOdevices;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import kernel.CPU;
import adt.CPUprocess;
/**
 * This class will listen to keyboard inputs on the
 * Java console.
 * 
 * @author Aaron Fung
 * 		   Chris Ren
 * @version 1.0
 */
public class Keyboard extends Thread {
	
	
	/**
	 * Blocking Queue used to keep track of processes requesting service.
	 */
	private BlockingQueue<CPUprocess> my_ioblocked_queue;
	
	/**
	 * The CPU
	 */
	private CPU my_cpu;
	
	/**
	 * A process that is requesting for service.
	 */
	private CPUprocess process;
	
	/**
	 * Used to read user input from the Java console.
	 */
	private BufferedReader input;
	
	/**
	 * Constructor for the Keyboard. Instantiate a buffer reader to read
	 * input from the Java console and sets up its own blocked queue.
	 * 
	 * @param the_cpu A reference to the CPU.
	 */
	public Keyboard(final CPU the_cpu) {
		input = new BufferedReader(new InputStreamReader(System.in));
		my_cpu = the_cpu;
		my_ioblocked_queue = new LinkedBlockingQueue<CPUprocess>();
	}

	/**
	 * Begin keyboard service. Monitors keyboard input
	 * from the Java console.
	 */
	public void run() {
		String keyboard_input = "";
		while (true) {
			try {
				keyboard_input = input.readLine().toLowerCase();
				if (!keyboard_input.isEmpty() && !keyboard_input.equals("x")) {
					System.out.println("Keyboard input detected.");
					System.out.println("I/O interrupt service requested.");
					initiateInterrupt();
				} else if (keyboard_input.equals("x") && !my_ioblocked_queue.isEmpty()) {
					CPUprocess temp = my_ioblocked_queue.poll();
					my_cpu.process_ready(temp);
					System.out.println("Keyboard service complete for " + temp.getPid());
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * Adds the process to keyboard's blocked queue.
	 * 
	 * @param the_process A Process requesting 
	 * 		  for service from the keyboard.
	 */
	public void addProcess(final CPUprocess the_process) {
		process = the_process;
		my_ioblocked_queue.add(process);
	}
	
	/**
	 * Signals that an interrupt has occurred 
	 * when a key event has happened.
	 */
	private void initiateInterrupt() {

		my_cpu.contextSwitch(CPU.Request.KEYBOARD_SER_DONE);
	}
	
	/**
	 * Signals that the interrupt has completed.
	 */
	public void deactivateInterrupt() {
	
		if (!my_ioblocked_queue.isEmpty()) {
			my_cpu.process_ready(my_ioblocked_queue.poll());
		}
	}
	
	/**
	 * Displays current processes in the keyboard's
	 * blocked queue.
	 */
	public void display() {
		System.out.println("\nKeyboard Blocked Queue:");
		for(CPUprocess p : my_ioblocked_queue)
		{
			System.out.print(p.getPid() + ", ");
		}
	}
}
